Copyright ã1994 by NeXT Computer, Inc.  All Rights Reserved.

NSException 

Inherits From:	NSObject

Conforms To:	NSCoding, NSCopying
NSObject (NSObject)

Declared In:	Foundation/NSException.h 

Class Description

The NSException class provides an object-oriented way for applications to announce and react to exceptional conditions.

An exceptional condition is one that interrupts the normal flow of program execution. Each application can interpret different types of conditions as exceptional. For example, one application might view as exceptional the attempt to save a file in a directory that's write-protected. In this sense, an exceptional condition can be equivalent to an error. Another application might interpret the user's keypress as an exceptional conditionÐan indication that a long-running process should be aborted.

Raising an Exception

Once an exceptional condition is detected, it must be propagated to the routine or routines that will handle it, a process referred to as ªraising an exception.º In the OpenStep exception handling system, exceptions are raised by instantiating an exception object and sending it a raise message.

Exception objects encapsulate:

·	a name. A short NSString that is used to uniquely identify the exception

·	a reason. A longer NSString that contains a ªhuman-readableº reason for the exception. This reason object is printed when the exception object is printed using the ª%@º format.

·	userInfo. An NSDictionary object that you can use to supply application-specific data to the exception handler. For example, if a function's return value caused the exception to be raised, you could pass the return value to the exception handler through the userInfo dictionary. Or, if the exception handler displays a panel in response to the exception, userInfo could contain the text string to be displayed in the panel.

Handling an Exception

Sending a raise message to an exception object initiates the propagation of the exception and passes data about it. Where and how the exception is handled depends on where you send the message from. Let's first look at a simple case.

In general, a raise message is sent to an exception object within the domain of an exception handler. An exception handler is a control structure created by the macros NS_DURING, NS_HANDLER, and NS_ENDHANDLER.

,

Figure 2-2. Exception Handling Domain and Handler

The section of code between NS_DURING and NS_HANDLER is the exception handling domain; the section between NS_HANDLER and NS_ENDHANDLER is the local exception handler. The normal flow of program execution is marked by the gray arrow; the code within the local exception handler is executed only if an exception is raised. Sending a raise message to an exception object causes program control to jump to the first executable line following NS_HANDLER, as indicated by the black arrow.

An exception can be raised directly within the exception handling domain, or indirectly from one of the methods or functions invoked from the domain. No matter how deeply in a call sequence an exception is raised, execution jumps to the local exception handler (assuming there are no intervening exception handlers, as discussed in the next section). In this way, exceptions raised at a low level can be caught at a high level.

If an exception is raised and execution begins within the local exception handler, it either continues until all appropriate statements are executed or the exception is raised again to invoke the services of an encompassing exception handler, as described in the next section.

If the exception isn't raised again, execution within the local exception handler continues until it leaves the local handler by:

·	ªFalling off the endº

·	Calling NS_VALRETURN()

·	Calling NS_VOIDRETURN

Note:  A simple return from the exception-handling domain is not permitted.

ªFalling off the endº is simply the normal execution pathway introduced above. After all appropriate statements within the domain are executed (and no exception is raised), execution continues on the line following NS_ENDHANDLER. Alternatively, you can return control to the caller from within the domain by calling NS_VALRETURN() or NS_VOIDRETURN, depending on whether you need to return a value.

You can't use goto or return() to exit an exception handling domainÐerrors will result. Nor can you use setjmp() and longjmp() if the jump entails crossing an NS_DURING statement. Since in many cases you won't know if the code that your program calls has exception handling domains within it, it's generally not recommended that you use setjmp() and longjmp() in your application.

Nested Exception Handlers

Exception handlers can be nested so that an exception raised in an inner domain can be treated by the local exception handler and any number of encompassing exception handlers. The following diagram illustrates the use of nested exception handlers, and is discussed in the text that follows.

,

Figure 2-3. Nested Exception Handlers

An exception raised within Function3's domain causes execution to jump to its local exception handler. In a typical application, this exception handler checks the values contained the NSException object to determine the nature of the exception. For exception types that it recognizes, the local handler responds and then sends a raise message to the exception object to pass notification of the exception to the handler above it (in this case, the handler in Function2). Function2's exception handler does the same and then raises the exception to Function1's handler. Finally, Function1's handler re-raises the exception. Since there's no exception handling domain above Function1, the exception is transferred to a default top-level error handler. For applications based on the Application Kit, this top-level handler invokes NSApplication's reportException: method, which writes an error message to the console.

An exception that's re-raised appears to the next higher handler just as if the initial exception had been raised within its own exception handling domain.

Raising an Exception Outside of an Exception Handler

If an exception is raised outside of any exception handler, it's intercepted by the uncaught exception handler, a function set by NSSetUncaughtExceptionHandler() and returned by NSUncaughtExceptionHandler(). You can change the way uncaught exceptions are handled by using NSSetUncaughtExceptionHandler() to establish a different procedure as the handler. However, because of the design of the Application Kit, it's rare for an exception to be raised outside of an exception handling domain. The NSApplication object's event loop itself is within an exception handling domain. On each cycle of the loop, the NSApplication object retrieves an event and sends an event message to the appropriate object in the application. Thus, the code you write for custom objects (as well as the code for Application Kit objects) is executed within the context of the event loop's exception handler. 

Predefined Exceptions

OpenStep predefines a number of exception names. These exceptions are listed in NSException.h; for example:

extern NSString *NSGenericException;
extern NSString *NSRangeException;
extern NSString *NSInvalidArgumentException;

For a complete list of global exception names, see the ªTypes and Constantsº sections of this manual. You can catch any of these exceptions from within your exception handler by comparing the exception's name with these predefined exception names.

Creating and Raising Exceptions

+ (NSException *)exceptionWithName:(NSString *)name
reason:(NSString *)reason	Creates an exception object, assigning it name as its name,
userInfo:(NSDictionary *)userInfo		reason as its human-readable explanation, and userInfo as arbitrary data that will accompany the exception.

+ (volatile void)raise:(NSString *)name	Creates and raises an exception with name name and 
format:(NSString *)format,...		a reason constructed from format and the following arguments in the manner of printf(). The user-defined information is nil. Invokes raise as part of its implementation.

+ (volatile void)raise:(NSString *)name	Creates and raises an exception with name name and
format:(NSString *)format		a reason constructed from format and the arguments in 
arguments:(va_list)argList		argList, in the manner of vprintf(). The user-defined information is nil. Invokes raise as part of its implementation.

- (id)initWithName:(NSString *)name	Initializes a newly allocated exception object, assigning it 
reason:(NSString *)reason		name as its name, reason as its human-readable
userInfo:(NSDictionary *)userInfo		explanation, and userInfo as arbitrary data that will accompany the exception.

- (volatile void)raise	Raises the exception, causing program flow to jump to the enclosing error handler.

Querying Exceptions

- (NSString *)name	Returns the exception's name. See exceptionWithName:reason:userInfo:.

- (NSString *)reason	Returns the exception's reason. See exceptionWithName:reason:userInfo:.

- (NSDictionary *)userInfo	Returns the exception's user-defined data. See exceptionWithName:reason:userInfo:.